#include "token.h"
#include <l8w8jwt/decode.h>
#include <l8w8jwt/encode.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define JWT_SECRET_KEY "my-secret-key"

system_error_code_t generate_jwt_token(const char *username, char **out_token, size_t *out_length)
{
    // 参数检查
    if (username == NULL || out_token == NULL || out_length == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 初始化参数
    struct l8w8jwt_encoding_params params;
    l8w8jwt_encoding_params_init(&params);
    
    // 设置签名算法
    params.alg = L8W8JWT_ALG_HS256;
    
    // 设置主体 sub 字段
    params.sub = (char *)username;
    
    // 设置签发时间 iat 字段
    params.iat = l8w8jwt_time(NULL);
    
    // 设置密钥
    params.secret_key = (unsigned char *)JWT_SECRET_KEY;
    params.secret_key_length = strlen(JWT_SECRET_KEY);
    
    // 设置输出
    params.out = out_token;
    params.out_length = out_length;
    
    // 编码
    int ret = l8w8jwt_encode(&params);
    if (ret != L8W8JWT_SUCCESS) {
        return SYSTEM_ERR_TOKEN_ENCODE_FAILED;
    }

    return SYSTEM_ERR_OK;
}

system_error_code_t is_valid_jwt_token(const char *username, const char *token)
{
    // 参数检查
    if (username == NULL || token == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    struct l8w8jwt_decoding_params params;
    l8w8jwt_decoding_params_init(&params);

    // 设置要解码的JWT
    params.jwt = (char *)token;
    params.jwt_length = strlen(token);

    // 设置验证算法
    params.alg = L8W8JWT_ALG_HS256;

    // 设置密钥
    params.verification_key = (unsigned char *)JWT_SECRET_KEY;
    params.verification_key_length = strlen(JWT_SECRET_KEY);

    // 验证签名，但不验证过期时间（因为我们没有设置exp）
    params.validate_exp = 0; 
    params.validate_iat = 0;
    params.validate_nbf = 0;

    enum l8w8jwt_validation_result validation_result;
    struct l8w8jwt_claim *claims = NULL;
    size_t claims_count = 0;
    int decode_ret = l8w8jwt_decode(&params, &validation_result, &claims, &claims_count);

    // 检查解码和签名验证结果
    if (decode_ret != L8W8JWT_SUCCESS || validation_result != L8W8JWT_VALID)
    {
        l8w8jwt_free_claims(claims, claims_count);
        return SYSTEM_ERR_TOKEN_INVALID;
    }

    // 签名有效，现在检查 'sub' 声明是否匹配
    struct l8w8jwt_claim *sub_claim = l8w8jwt_get_claim(claims, claims_count, "sub", 3);

    system_error_code_t result = SYSTEM_ERR_OK;
    if (sub_claim == NULL || 
        sub_claim->type != L8W8JWT_CLAIM_TYPE_STRING ||
        sub_claim->value_length != strlen(username) ||
        strncmp(sub_claim->value, username, sub_claim->value_length) != 0)
    {
        result = SYSTEM_ERR_TOKEN_INVALID;
    }

    l8w8jwt_free_claims(claims, claims_count);

    return result;
}

system_error_code_t validate_jwt_and_get_username(const char *token, char **out_username)
{
    if (token == NULL || out_username == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    struct l8w8jwt_decoding_params params;
    l8w8jwt_decoding_params_init(&params);

    params.jwt = (char *)token;
    params.jwt_length = strlen(token);
    params.verification_key = (unsigned char *)JWT_SECRET_KEY;
    params.verification_key_length = strlen(JWT_SECRET_KEY);
    params.alg = L8W8JWT_ALG_HS256;
    params.validate_exp = 0;
    params.validate_iat = 0;
    params.validate_nbf = 0;

    enum l8w8jwt_validation_result validation_result;
    struct l8w8jwt_claim *claims = NULL;
    size_t claims_count = 0;
    int decode_ret = l8w8jwt_decode(&params, &validation_result, &claims, &claims_count);

    if (decode_ret != L8W8JWT_SUCCESS || validation_result != L8W8JWT_VALID)
    {
        l8w8jwt_free_claims(claims, claims_count);
        return SYSTEM_ERR_TOKEN_DECODE_FAILED;
    }

    struct l8w8jwt_claim *sub_claim = l8w8jwt_get_claim(claims, claims_count, "sub", 3);
    if (sub_claim == NULL || sub_claim->type != L8W8JWT_CLAIM_TYPE_STRING)
    {
        l8w8jwt_free_claims(claims, claims_count);
        return SYSTEM_ERR_TOKEN_INVALID;
    }

    *out_username = (char *)calloc(sub_claim->value_length + 1, sizeof(char));
    if (*out_username == NULL) {
        l8w8jwt_free_claims(claims, claims_count);
        return SYSTEM_ERR_OUT_OF_MEMORY;
    }
    
    strncpy(*out_username, sub_claim->value, sub_claim->value_length);
    l8w8jwt_free_claims(claims, claims_count);

    return SYSTEM_ERR_OK;
}